#include<opencv2/opencv.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include "opencv2/imgcodecs.hpp"
#include<iostream>
#include<ctime>

using namespace cv;
// 图像的读取（imread），显示(imshow)，保存(imwrite)
int test_01()
{
    //  CV_LOAD_IMAGE_UNCHANGED    加载原图
    //  cv::IMREAD_GRAYSCALE  加载灰度图片
    //  cv::IMREAD_COLOR    加载rgb图片
    cv::Mat src = cv::imread("./doc/unchange/meinv01.webp",cv::IMREAD_GRAYSCALE);    // 读取
    if(src.empty())
    {
        perror("cv_load_error\n");
        return -1;
    }
    cv::namedWindow("load gril image",CV_WINDOW_NORMAL);   // 创建一个窗口；（非必要的）
    cv::imshow("load gril image",src);    // 在创建的窗口上进行 显示
    int k = cv::waitKey(0);   // 键盘绑定，等待键盘按下
    if(k == 's')
        cv::imwrite("./doc/change/huidumeinv.png",src);  // 保存图片
    else
        cv::destroyAllWindows();
    return 0;
}

// cv :: cvtColor将图像从BGR转换为灰度格式

int test_02()
{
    cv::Mat src = cv::imread("./doc/unchange/meinv01.webp",IMREAD_COLOR);
    if(src.empty())
    {
        perror("img read fail\n");
        return -1;
    }
    cv::Mat gray_img;
    cv::cvtColor(src,gray_img,COLOR_BGR2GRAY);
    cv::namedWindow("img",CV_WINDOW_NORMAL);
    cv::imshow("img",gray_img);
    if(cv::waitKey(0) == 's')
    {
        cv::imwrite("./doc/change/meinv1114.png",gray_img);
    }
    else{
        cv::destroyAllWindows();
    }
    return 1;
}



// 视屏的读取、显示、捕捉、保存
int test_03()
{

    cv::VideoCapture videosrc = cv::VideoCapture(0);
    cv::Mat video_frame;
    cv::Mat img_frame;
    if(!videosrc.isOpened())
    {
        perror("videoCapture open fail\n");
        return -1;
    }
    while(1)
    {
        // 逐帧捕获
        bool ret = videosrc.read(video_frame);
        if(ret == 0)
        {
            perror("read frame error\n");
            return -1;
        }
        cv::cvtColor(video_frame, img_frame, cv::COLOR_BGR2GRAY);
        cv::imshow("show",img_frame);
        if(cv::waitKey(1) == 'q')    // 0 会阻塞    1 不阻塞
        {
            break;
        }
    }
    videosrc.release();
    cv::destroyAllWindows();
    return 0;
}


/* 保存视屏 */
int test_04()
{
    cv::VideoCapture cat = cv::VideoCapture(0);
    cv::Mat img;
    cv::VideoWriter v_w;
    if(!cat.isOpened())
    {
        perror("open carm fail\n");
        return -1;
    }
    cat>>img;//获取图像
    //检测是否成功获取图像
    if(img.empty()){//判断有没有读取图像成功
        std::cout<<"没有获取到图像"<<std::endl;
        return -1;
    }
    bool isColor=(img.type()==CV_8UC3);//判断相机(视频)是否为彩色
    int coder=cv::VideoWriter::fourcc('M','J','P','G');//选择编码格式
    double fps=25.0;//设置视频帧率
    v_w.open("./doc/output_video01.avi",coder,fps,img.size(),isColor);//创建保存视频文件的视频流
    if(!v_w.isOpened()){
        std::cout<<"打开视频文件失败，请确认是否为合法输入"<< std::endl;
        return -1;
    }
    while (1){
        //检测是否执行完毕
        if(!cat.read(img)){
            std::cout<<"摄像头断开连接或者视频读取完成"<<std::endl;
            break;
        }
        v_w.write(img);
        imshow("Live",img);
        char c=waitKey(50);
        if(c=='q'){
            break;
        }
    }
    cat.release();
    v_w.release();

}

/* 读取视屏 */
int test_05()
{
    cv::Mat img;
    cv::VideoCapture video("./doc/output_video01.avi");
    if(!video.isOpened())
    {
        std::cout << "file open error" << std::endl;
        return -1;
    }
    while(video.read(img))
    {
        if(img.empty())
        {
            perror("read video file fail\n");
            return -1;
        }
        cv::imshow("LIVE",img);
        if(cv::waitKey(75) == 'q')
        {
            break;
        }
    }
    video.release();
    return 0;
}
/* 画各种线条 */
#define img_size 512
/* 画线*/
void m_line(cv::Mat img,cv::Point start, cv::Point end)
{
    cv::line(img,start,end,Scalar( 255, 0, 0 ),5,LINE_8);   // 容器  开始  结束 颜色 厚度 LINE_8 == 连接线
}

/*画矩形*/
void m_rectAngle(cv::Mat img, cv::Rect start)
{
    cv::rectangle(img,start,Scalar(0, 255, 0),3);
}

/* 画圆 */
void m_cricle(cv::Mat img,cv::Point cent, int ridus)
{
    cv::circle(img,cent,ridus,Scalar(0,0,255),3);
}

/* 画椭圆 */
void m_ellip(cv::Mat img, const cv::RotatedRect box)
{
    cv::ellipse(img,box,Scalar(255,255,0),2);
}

/* 图像添加文字 */
void m_put_text(cv::Mat img, const cv::String text, cv::Point org, int fontFace, double fontScale)
{
    cv::putText(img,text,org,fontFace,fontScale,Scalar(255,255,255),4);
}

void test_06()
{
    cv::Mat img ;
    img = cv::Mat::zeros( img_size, img_size, CV_8UC3 );

    m_line(img,cv::Point(10,10),cv::Point(250,250));
    m_line(img,cv::Point(250,250),cv::Point(10,490));

    m_rectAngle(img,cv::Rect(10,135,120,230));

    m_cricle(img,cv::Point(300,250),50);

    m_ellip(img,cv::RotatedRect(cv::Point(300,100),Size2f(200,50),0));    // 中心点 ， 长轴短轴 ， 旋转角度
    m_ellip(img,cv::RotatedRect(cv::Point(300,100),Size2f(200,50),45));
    m_ellip(img,cv::RotatedRect(cv::Point(300,100),Size2f(200,50),90));
    m_ellip(img,cv::RotatedRect(cv::Point(300,100),Size2f(200,50),135));

    m_put_text(img,"SunJianZhao",cv::Point(250,400),1,2.5);
    cv::imshow("huaTu",img);
    cv::waitKey(0);
}


/* 画笔------鼠标事件 */
cv::Mat cat;
cv::Mat img;
void mouse_call(int event, int x, int y, int flags, void* param)
{
    if(event == CV_EVENT_LBUTTONDOWN)
    {
        img.copyTo(cat);
        m_rectAngle(cat,cv::Rect(x,y,25,25));
        cv::imshow("image",cat);
    }
    else if(event == CV_EVENT_RBUTTONDOWN)
    {
        img.copyTo(cat);
        m_cricle(cat,cv::Point(x,y),25);
        cv::imshow("image",cat);
    }
}

int test_07()
{
    img = cv::Mat::zeros(img_size,img_size,CV_8UC3);
    cv::namedWindow("image");
    // 设置鼠标回调
    cv::setMouseCallback("image",&mouse_call,0);
    while(1) {
        cv::imshow("image",img);
        if(cv::waitKey(0) == 'q')
        {
            break;
        }
    }
    return 0;
}


/* 轨迹栏 */

static void track_call_back(int ,void *)
{
    printf("track callback func \n");
}

int test_08()
{
    cv::Mat img = cv::Mat::zeros(img_size,img_size,CV_8UC3);
    cv::Mat meinv = cv::imread("./doc/unchange/meinv01.webp",IMREAD_COLOR);
    int r,g,b;
    int m_switch;
    cv::namedWindow("image");
    cv::createTrackbar("R","image",0,255);
    cv::createTrackbar("G","image",0,255);
    cv::createTrackbar("B","image",0,255);
    cv::createTrackbar("switch","image",0,1,&track_call_back);  /* 轨迹栏做开关 */

    while (1)
    {
        r = cv::getTrackbarPos("R","image");
        g = cv::getTrackbarPos("G","image");
        b = cv::getTrackbarPos("B","image");  
        m_switch = cv::getTrackbarPos("switch","image");
        img = cv::Scalar(b,g,r);
        if(m_switch)
        {
            meinv.copyTo(img);
        }
        else {
            img = cv::Scalar(b,g,r);
            cv::circle(img,cv::Point(250,250),100,Scalar(255-b,255-g,255-r),3);
        }
        cv::imshow("image",img);
        if (cv::waitKey(1) == 'q')
        {
            break;
        }
        
    }

    return 0;
}


/* 图像基本操作 */
// 访问像素值
// 设置感兴趣的 ROI 
int test_09()
{
    cv::Mat img = cv::imread("./doc/unchange/meinv01.webp", IMREAD_COLOR);
    cv::Mat imgout = img.clone();
    int dev = 10;
    // 通过迭代器来遍历原图像，并修改像素值
    /*
      也可以使用 img.cols 和 img.rows 来获取行和列 进行循环改变像素值
    */
    for(auto iter = imgout.begin<Vec3b>(); iter != imgout.end<Vec3d>();iter++)
    {
        (*iter)[0] = (*iter)[0] / dev * dev / 4 /*+ dev / 2*/;    // B
        (*iter)[1] = (*iter)[1] / dev * dev / 4 /*+ dev / 2*/;    // G
        (*iter)[2] = (*iter)[2] / dev * dev / 4 /*+ dev / 2*/;    // R  
    }
    for(auto iter = imgout.begin<Vec3b>(); iter != imgout.end<Vec3d>();iter++)
    {
        (*iter)[0] = (*iter)[0] / dev * dev /*+ dev / 2*/;    // B
        (*iter)[1] = (*iter)[1] / dev * dev /*+ dev / 2*/;    // G
        (*iter)[2] = (*iter)[2] / dev * dev /*+ dev / 2*/;    // R  
        (*iter)[0] = (*iter)[1] = (*iter)[2] = std::max((*iter)[0],std::max((*iter)[1],(*iter)[2]));

    }
    // 显示图像
    cv::imshow("outputImg", imgout);
    cv::waitKey(0);
    return 0;
}


// 获取图像属性   ------- 行数、列数、通道数、数据类型、像素 
int test_10()
{
    cv::Mat img = cv::imread("./doc/unchange/meinv01.webp", IMREAD_COLOR);
    auto size = img.size();    // 图像的像素总数
    auto rows = img.rows;      // hang
    auto cols = img.cols;      // lie
    auto channel = img.channels();   // tong dao 

    std::cout << size << "  " << rows << "  " << cols << "  " << channel << std::endl;

    return 0;
}
// 图像中感兴趣的地方ROI
// 目的：缩小搜索区域 提高性能 提高准确性
// 步骤： 读取RGB图片-----  转换成HIV ---------获取ROI区域的mask ------------ 提取ROI区域
int test_11()
{   
    cv::Mat img = cv::imread("./doc/unchange/meinv01.webp", IMREAD_COLOR);
    cv::Mat hsv;
    cv::Mat mask;
    cv::Mat timg;
    cv::cvtColor(img,hsv,COLOR_BGR2HLS);
    int r,g,b;
    int ru,gu,bu;
    cv::namedWindow("mask");
    cv::createTrackbar("R","mask",0,255);
    cv::createTrackbar("G","mask",0,255);
    cv::createTrackbar("B","mask",0,255);
    cv::createTrackbar("RU","mask",0,255);
    cv::createTrackbar("GU","mask",0,255);
    cv::createTrackbar("BU","mask",0,255);
    while(1)
    {
        r = cv::getTrackbarPos("R","mask");
        g = cv::getTrackbarPos("G","mask");
        b = cv::getTrackbarPos("B","mask");
        ru = cv::getTrackbarPos("RU","mask");
        gu = cv::getTrackbarPos("GU","mask");
        bu = cv::getTrackbarPos("BU","mask");
        cv::inRange(hsv, Scalar(r,g,b), Scalar(ru,gu,bu),mask);    // 二值化处理
        cv::imshow("mask",mask);
        if(cv::waitKey(1) == 'q')
        {
            break;
        }
    }
    
    // 逻辑取反
    cv::bitwise_not(mask,mask);
    cv::imwrite("./doc/change/meinvmask.jpg",mask);
    cv::bitwise_and(img,img,timg,mask=mask);
    cv::imshow("timg1", timg);

    cv::waitKey(0);

    return 0;
}
/* 图像算术运算 */
// 加法 、 融合 、 安位运算
// 加logo
int test_12()
{
    double alpha = 0.5;   // G(x)= (1 - \alpha)f_0(x)+ \alpha f_1(x)
    double beta = 0;
    cv::Mat img = cv::imread("./doc/unchange/meinv01.webp", IMREAD_COLOR);
    cv::Mat backimg = cv::imread("./doc/unchange/daotian.jpeg", IMREAD_COLOR);
    cv::Mat dst;
    // dst = backimg.clone();
    // 图像混合
    if(img.empty() || backimg.empty())
    {
        std::cout << "photo load error!!!" << std::endl;
        return 0;
    }
    beta = 1 - alpha;
    cv::resize(backimg,backimg,Size(img.cols,img.rows));    // 融合的图像大小必须是一致的，所以需要调整图像大小
    cv::namedWindow("dst");
    cv::createTrackbar("ALPHA","dst",0,100);
    while(1)
    {
        alpha = cv::getTrackbarPos("ALPHA","dst") / 100.0;
        beta = 1 - alpha;
        cv::addWeighted(img,alpha,backimg,beta,0.0,dst);    // 两张图像进行不同权重融合
        cv::imshow("dst",dst);
        if(cv::waitKey(1) == 'q')
        {
            break;
        }
    }
    // cv::add(img,backimg,dst);
    return 0;
}


























